package com.quan.commons.tools.sms;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.quan.commons.core.properties.SystemValueProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 阿里短信发送工具
 * @author yhaoquan
 */
@Slf4j
@Component
public class ALiYunSMSTools {

    @Autowired
    private SystemValueProperties properties;


    /**
     * 发送短信
     * @param signIndex 配置文件中的短信签名索引，0开始
     * @param phone     手机号
     * @param msg       短信模板内容，如：map.put("code", "1234")
     * @return
     * @throws Exception
     */
    public boolean baseSMSSend(int signIndex, String phone, Map<String, Object> msg) throws Exception {
        SystemValueProperties.Aliyun.Sms.Signs signs = this.properties.getAliyun().getSms().getSigns().get(signIndex);
        if (null != signs) {
            return baseSMSSend(signs.getName(), signs.getTemplateCode(), phone, msg);
        }
        throw new Exception("未配置短信签名和短信模板");
    }


    /**
     * 发送短信
     * @param phone 手机号
     * @param msg   短信模板内容，如：map.put("code", "1234")
     * @return
     * @throws Exception
     */
    public boolean baseSMSSend(String phone, Map<String, Object> msg) throws Exception {
        SystemValueProperties.Aliyun.Sms.Signs signs = this.properties.getAliyun().getSms().getSigns().get(0);
        if (null != signs) {
            return baseSMSSend(signs.getName(), signs.getTemplateCode(), phone, msg);
        }
        throw new Exception("未配置短信签名和短信模板");
    }

    /**
     * 发送短信
     * @param sign         配置文件中的短信签名索引，0开始
     * @param templateCode 短信模板code
     * @param phone        手机号
     * @param msg          短信模板内容，如：map.put("code", "1234")
     * @return
     * @throws Exception
     */
    public boolean baseSMSSend(String sign, String templateCode, String phone, Map<String, Object> msg) throws Exception {
        log.info("==>发送短信【开始】");
        String result_code;
        String content = JSON.toJSONString(msg);
        // 设置第三方交接唯一ID、第三方交接唯一ID加密过的、端点
        try {
            // 可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");

            // 初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
                    properties.getAliyun().getSms().getKeyId(), properties.getAliyun().getSms().getKeySecret());
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com");
            IAcsClient acsClient = new DefaultAcsClient(profile);

            // 组装请求对象
            SendSmsRequest request = new SendSmsRequest();
            // 使用post提交
            request.setMethod(MethodType.POST);
            // 必填:待发送手机号。支持以逗号分隔的形式进行批量调用，批量上限为1000个手机号码,
            // 批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式；
            // 发送国际/港澳台消息时，接收号码格式为00+国际区号+号码，如“0085200000000”
            request.setPhoneNumbers(phone);
            // 必填:短信签名-可在短信控制台中找到
            request.setSignName(sign);
            // 必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(templateCode);
            // 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,
            // 比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
            request.setTemplateParam(content);

            // 请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            result_code = sendSmsResponse.getCode();
            log.info("==>状态:{}", "：" + sendSmsResponse.getCode());

        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云短信服务异常:{}", e.getMessage());
            result_code = "fail";
        }

        if (result_code != null && result_code.equals("OK")) {
            // 发送成功
            log.info("==>发送短信【成功】==》手机号：{}，短信模板：{}，短信内容：{}", phone, templateCode, content);
            return true;
        } else {
            // 发送失败
            assert result_code != null;
            switch (result_code) {
                case "fail":
                    log.error("发送验证码失败:{}", "短信服务功能异常。请联系工程师处理");
                    break;
                case "isv.OUT_OF_SERVICE":
                    log.error("发送验证码失败:{}", "业务停机(请先查看账户余额，若余额大于零，则请联系工程师处理)");
                    break;
                case "isv.MOBILE_NUMBER_ILLEGAL":
                    log.error("发送验证码失败:{}", "非法手机号。PhoneNumbers参数请传入11位国内号段的手机号码");
                    break;
                case "isv.MOBILE_COUNT_OVER_LIMIT":
                    log.error("发送验证码失败:{}",
                            "手机号码数量超过限制。短信接收号码," + "支持以英文逗号分隔的形式进行批量调用，批量上限为1000个手机号码，" + "PhoneNumbers参数单次调用不传入过多接收号码");
                    break;
                case "isv.TEMPLATE_MISSING_PARAMETERS":
                    log.error("发送验证码失败:{}", "模板缺少变量。请联系工程师处理");
                    break;
                case "isv.BUSINESS_LIMIT_CONTROL":
                    log.error("发送验证码失败:{}", "业务限流。将短信发送频率限制在正常的业务流控范围内，" + "默认流控：短信验证码 ：使用同一个签名，对同一个手机号码发送短信验证码，"
                            + "支持1条/分钟，5条/小时 ，累计10条/天。");
                    break;
                case "isv.INVALID_JSON_PARAM":
                    log.error("发送验证码失败:{}", "JSON参数不合法，只接受字符串值");
                    break;
                case "isv.BLACK_KEY_CONTROL_LIMIT":
                    log.error("发送验证码失败:{}", "黑名单管控");
                    break;
                case "isv.PARAM_LENGTH_LIMIT":
                    log.error("发送验证码失败:{}", "参数超出长度限制,单个变量长度限制在20字符内。");
                    break;
                case "isv.PARAM_NOT_SUPPORT_URL":
                    log.error("发送验证码失败:{}", "不支持URL");
                    break;
                case "isv.AMOUNT_NOT_ENOUGH":
                    log.error("发送验证码失败:{}", "账户余额不足。转入金额不足以发送当前信息，" + "确保余额足够发送当前短信");
                    break;
                case "isv.TEMPLATE_PARAMS_ILLEGAL":
                    log.error("发送验证码失败:{}", "模板变量里包含非法关键字");
                    break;
                case "isp.RAM_PERMISSION_DENY":
                    log.error("发送验证码失败:{}",
                            "RAM权限DENY,当提示RAM权限不足时，" + "就需要给当前使用的AK对应子账号进行授权：AliyunDysmsFullAccess（权限名称）。"
                                    + "具体权限授权详见：https://help.aliyun.com/document_detail/55764.html"
                                    + "?spm=5176.product44282.6.548.bKZJL2");
                    break;
                case "isv.INVALID_PARAMETERS":
                    log.error("发送验证码失败:{}", "参数异常,对照文档，检查参数格式。请联系工程师处理");
                    break;
                case "InvalidTimeStamp.Expired":
                    log.error("发送验证码失败:{}", "时间戳错误，发出请求的时间和服务器接收到请求的时间" + "不在15分钟内。经常出现该错误的原因是时区原因造成的,目前网关使用的时间是GMT时间");
                    break;
                case "isv.SMS_SIGNATURE_ILLEGAL":
                    log.error("发送验证码失败:{}", "短信签名不合法.SignName请传入审核通过的签名内容，"
                            + "签名见：https://dysms.console.aliyun.com/dysms.htm#/sign。请联系工程师处理");
                    break;
                case "isp.SYSTEM_ERROR":
                    log.error("发送验证码失败:{}", "请重试。如仍存在此情况请反馈工程师查看");
                    break;
            }
        }
        return false;
    }

}
